/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETF3DTrack
  \brief class for a 3D track
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-11-19
  \date 2021-11-30 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-11-19   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include "ETF3DTrack.h"
#include "ETFVTrack.h"
#include "ETFMsg.h"
#include "ETFMath.h"

using std::cout;
using std::endl;

ETF3DTrack::ETF3DTrack() : TObject(){
  Initialize();
} // end ctor

// copy ctor
ETF3DTrack::ETF3DTrack(const ETF3DTrack &t) : TObject(t){
  *this = t;
} // end copy ctor
// assignment ctor
ETF3DTrack &ETF3DTrack::operator=(const ETF3DTrack &t){
  if(&t == this) return *this;

  fTracks = t.fTracks;
  fK1 = t.fK1; fB1 = t.fB1;
  fK2 = t.fK2; fB2 = t.fB2;
  fTOTAvrg = t.fTOTAvrg;
  memcpy(fXMiss3D, t.fXMiss3D, sizeof(fXMiss3D));

  return *this;
} // end assignment ctor

ETF3DTrack::~ETF3DTrack(){}

void ETF3DTrack::Initialize(){
  fTracks.clear();
  fHitPosXMap.clear(); fHitPosYMap.clear();
  fK1 = fB1 = fK2 = fB2 = fTOTAvrg = -999.;
  for(double &x : fXMiss3D) x = -999.;
} // end member function Initialize

// k1 in angle: atan(k1)/DEGREE
double ETF3DTrack::GetAng1() const{
  return ETFMath::ang(GetK1());
} // end member function GetAng1
// k2 in angle: atan(k2)/DEGREE
double ETF3DTrack::GetAng2() const{
  return ETFMath::ang(GetK2());
} // end member function GetAng1

void ETF3DTrack::GetHitPos(const string &d, double &lx, double &ly) const{
  lx = GetHitPosX(d);
  ly = GetHitPosY(d);
} // end member function GetHitPo
double ETF3DTrack::GetHitPosX(const string &d) const{
  if(!fHitPosXMap.count(d))
    ETFMsg::Warn(GetName(), "GetHitPosX: no record for det %s", d.c_str());
  return fHitPosXMap.at(d);
} // end member function GetHitPosX
double ETF3DTrack::GetHitPosY(const string &d) const{
  if(!fHitPosYMap.count(d))
    ETFMsg::Warn(GetName(), "GetHitPosY: no record for det %s", d.c_str());
  return fHitPosYMap.at(d);
} // end member function GetHitPosY

void ETF3DTrack::SetHitPos(const string &d, double lx, double ly){
  fHitPosXMap[d] = lx; fHitPosYMap[d] = ly;
} // end member function SetHitPos
// assign hit pos at det's central plane
void ETF3DTrack::UpdateHitPos(ETFDetector *d){
  const string name = d->GetName();
  const double p1[4] = {GetK1(), GetB1(), GetK2(), GetB2()};
  d->GetHitPositionL(p1, fHitPosXMap[name], fHitPosYMap[name]);
  if(fTracks.size() < 3){ // a ta-zone track
    fHitPosXMap[name] += d->GetX(); // so we'd rather want the absolute position
    fHitPosYMap[name] += d->GetY(); // to see how much the beam is off the z-axis
  } // end if
} // end member function UpdateHitPos

void ETF3DTrack::SetTrack(TrackType type, ETFVTrack *trk){
  fTracks[type] = trk;
} // end mmeber function SetTrack

ETFVTrack *ETF3DTrack::GetTrack(TrackType type) const{
  return fTracks.at(type);
} // end mmeber function SetTrack

void ETF3DTrack::SetXMiss3D(double *p){
  memcpy(fXMiss3D, p, sizeof(fXMiss3D));
} // end member function SetXMiss3D

void ETF3DTrack::SetId(int id){
  fName = ETFMsg::Form("3DTrack_#%d", id);
} // end member function SetId

void ETF3DTrack::Print(const char *) const{
  cout << "\033[32;1m___________3D Track " << GetName();
  cout << " ____________\033[0m" << endl;
  cout << "k1: " << fK1 << " b1: " << fB1 << " k2: " << fK2 << " b2: " << fB2 << endl;
  cout << "fXMiss3D: ";
  for(const auto &x : fXMiss3D) cout << x << ' ';
  cout << endl;

  static const TrackType t[3] = {TrackType::kX, TrackType::kU, TrackType::kV};
  for(int i = 0; i < 3; i++) if(fTracks.count(t[i])) fTracks.at(t[i])->Print();
} // end member function Print

void ETF3DTrack::AssignTOT(){
  static const TrackType t[3] = {TrackType::kX, TrackType::kU, TrackType::kV};

  int nh = 0; fTOTAvrg = 0.;
  for(int i = 0; i < 3; i++) if(fTracks.count(t[i])){
    ETFVTrack *trk = fTracks.at(t[i]);
    fTOTAvrg += trk->tot() * trk->GetNofHits();
    nh += trk->GetNofHits();
  } // end for
  fTOTAvrg /= nh;
} // end member AssignTOT
